package org.sang.config;

import org.sang.service.HrService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;

/**
 * Created by sang on 2017/12/28.
 */
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true) //开启方法上的认证:这将使得可以在方法上使用注解@PreAuthorize
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    HrService hrService;
    @Autowired
    CustomMetadataSource metadataSource;
    @Autowired
    UrlAccessDecisionManager urlAccessDecisionManager;
    @Autowired
    AuthenticationAccessDeniedHandler deniedHandler;
    @Autowired
    CustomAuthenticationFailureHandler customAuthenticationFailureHandler;
    @Autowired
    CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;

    @Override //这里可以配置该项目与用户的关联，也称作认证
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        /*
        * 用户认证
        * 1、hrService.loadUserByUsername查找是否有该用户
        * 2、对前台传过来的明文密码进行加密前跟储存的密码进行对比，是否一致。
        * */
        auth.userDetailsService(hrService) //注册自己定制的UserDetailsService
                .passwordEncoder(new BCryptPasswordEncoder()); // 配置密码加密器
    }
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/index.html", "/static/**", "/login_p"); //无需验证的资源
    }

    @Override  //这里可以配置我们对于一个HttpSecurity需要通过什么样子的安全认证
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests() //获取请求方面的验证器，定义哪些URL需要被保护、哪些不需要被保护
        .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
            @Override
            public <O extends FilterSecurityInterceptor> O postProcess(O o) {
                o.setSecurityMetadataSource(metadataSource);  //注册一个自定义的权限资源实现类
                o.setAccessDecisionManager(urlAccessDecisionManager); //注册一个自定义的权限决策实现类
                return o;
            }
        })
        .and()
        .formLogin() //通过表单登录认证
                .loginPage("/login_p") //注册自定义的登录页面URL
                .loginProcessingUrl("/login") //获取登录请求的URL
        .usernameParameter("username").passwordParameter("password")
        .failureHandler(customAuthenticationFailureHandler) //认证失败的自定义处理器
        .successHandler(customAuthenticationSuccessHandler) //认证成功的自定义处理器
        .permitAll() //登录请求给予通过认证
        .and()
        .logout().permitAll() // 访问当前配置的路径可通过认证
        .and().csrf().disable() //关闭csrf，默认开启，开启的话ajax和表单提交等都需要提供一个token
        .exceptionHandling()
                .accessDeniedHandler(deniedHandler);//抛出权限控制异常的处理器
    }
}